fix(stall): bound the verify retrieve separately from the create (X1D re-ship loop) #37
+381
−15
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
What
ship_object's post-create round-trip verify retrieve shared the create-sideHTAR_STALL_SECONDS(2 h) silence budget. It now has its own bound,retrieve_stall_seconds, whose default lives in data (stall_defaults.json, 21600 s = 6 h) and which a per-asset config may override.Why
A create streams per-file progress, so silence there is a genuine hang. A retrieve is silent by design while HPSS queues and stages the tape. On a large routed shard the shared bound was killing healthy retrieves.
Observed —
repository_X1D_3_metabolomics_rawspectra, one 6,624,961,024-byte shard:htar -cvfsucceeded every run; the retrieve was killed at exactly 7200 s on both attempts (~8 h/job, exit 1);poll: 7191.9s since last activity (stall limit 7200s)thenactivity resumed after 7200.1s silence (+73 bytes)— the retrieve was healthy, 0.1 s past the kill line;(Separate and already resolved: the 2026-08-01 HPSS outage produced a different mode,
htar create failed (rc=71). Not conflated here.)Changes
stall_defaults.json(new, committed) — the default retrieve budget, with the incident recorded beside it. 6 h is ~3x the one observed silence gap and stays well inside the 48 h Slurm walltime even if both retrieve attempts burn their full budget.load_stall_defaults()— fails loud on a missing/malformed/invalid file; no code-side fallback.load_configreads it lazily, so a config that pinsretrieve_stall_secondsneeds no defaults file, and validates a per-asset override.ship_object(..., retrieve_stall_seconds)— required; raises before anyhtar/hsicall rather than silently reinstating 2 h. Threaded through theship_oneclosure (positionally — the local/globusrundispatcher forwards positional args only).HTAR_STALL_SECONDS, documented at both constants, inconfig.example.json, and in CLAUDE.md invariant docs: RFC — staged-hybrid incremental backup (Phase 2 = size-routing/append) #7.Tests
New
tests/test_retrieve_stall_config.py: the defaults-file contract (including the default must exceed the create bound — a smaller value would re-open the loop while looking configured),load_configdefault/override/validation, that the retrieve calls carry the configured bound while the create does not, and that an absent/invalid value raises before any tape work. Existingship_objectcallers in three test files updated. Full suite: 423 passed.Scope / deploy notes
fortress/repo_backup.py), shipped alongside.git pullon the engine checkout, sostall_defaults.jsontravels witharchive.py. Copyingarchive.pyalone would make every config load fail loud — by design, but worth knowing.gated-data-remediationprotocol, provenance record first, and only after one verify actually passes.